package com.cskaoyan.javase.oop3._0abstract._1basic;

/**
 * 在继承体系中，从祖先类开始，随着一个个子类的定义，子类变得越来越具体，而祖先类则更具有一般性和抽象性。
 *      在这种情况下，为了体现祖先类在设计上的抽象性，我们只将该类作为派生其他类的父类，而不能创建对象实例。
 *      这个时候，这样的类，我们称之为抽象类。
 *
 * 抽象类是作为继承体系中,祖先类而存在的.
 * 所以:
 *      要想使用抽象类,首先要考虑继承层次,必须是一个祖先类,才能将它声明为抽象类.
 *      一般来说,抽象类不应该再继承别的类了(Object类除外,抽象类也会继承Object,因为它还是一个类)
 *
 *
 * 抽象类的特点我们主要从以下角度：
 * 抽象类的定义语法:
 * [修饰符列表] abstract class 类名{
 *     //类体
 * }
 *      1.类名命名特点
 *          抽象类仍然是一个类,仍然要"大驼峰式的书写",而且最好"见名知意"
 *          为了体现抽象类的特殊性,会在命名抽象类时,主动在抽象类命名前加"Abstract"或者"Base"
 *              表示它是一个抽象类
 *              这种命名建议使用
 *
 *       2.能用哪些修饰符？
 *              访问权限修饰符是可以的,但是只有两种访问级别,和类是一样的
 *              尤其注意final是不能修饰抽象类
 *       3.成员特点
 *          普通成员(变量和方法)
 *          静态成员(变量和方法)
 *              抽象类中可以定义普通成员和静态成员
 *              这一点和普通类没有区别.
 *
 *              注：抽象类虽然不能创建对象，但是它有子类，这些具体实现方法可以让子类继承，子类可以选择直接使用，也可以选择重写，选择的权力在子类手上
 *              （假如一个方法在抽象类的多个子类中都需要被使用，那么就可以提取到抽象类中作为一个默认实现）
 *
 *          抽象类可以不可以没有抽象方法?
 *              语法上来说,抽象类完全可以没有抽象方法
 *              有些程序员会出于禁止创建对象的目的将类设置为抽象类,这种做法是错误的,抽象类是作为继承中顶层父类而存在的,不要出于别的目的设置抽象类!
 *              如果希望一个类不能创建对象,直接私有化构造器即可.
 *              但是,抽象类的定义本身就是为了抽象方法而来的,抽象类没有抽象方法没有任何意义,不如定义普通类
 *              总之:
 *              抽象类就应该有抽象方法.
 *
 *          抽象方法
 *              语法:
 *              [修饰符列表] abstract 返回值类型 方法名(形参列表);
 *              抽象类中的抽象方法,必须强制它的普通子类实现,所以抽象方法在抽象类中,起到"占位符"的作用.
 *              抽象类的所有普通子类都必须强制实现抽象方法
 *
 *          构造器
 *              思考:
 *              抽象类不能创建对象,它需要构造器吗?它有构造器吗?
 *              构造器不是用来创建对象的,是用来给成员变量赋值的
 *              虽然抽象类自己不能创建对象赋值,但是子类对象的初始化,需要依赖于父类的构造器
 *              所以抽象类和普通类一样,也是有构造器的,自己不能用,给子类对象初始化用.
 *
 *              判断题:
 *              在Java中,任何类都有构造器.
 *              这是对的,不管是普通类 抽象类
 *              不管是否手动定义构造器
 *              一个类都有构造器
 *
 *          代码块
 *              构造代码块: 有
 *              静态代码块: 也有
 *
 * 以上,总结:
 *      抽象类,抽象类,就是一个可以定义抽象方法的普通类,普通类中有的,抽象类中都有,还多了一个抽象方法
 *
 *      辨析:
 *      随便找一个类,不考虑创建对象,直接将它声明为abstract,是完全可以的,没有任何问题.
 *
 * 抽象类和普通类的继承,抽象类和普通类之间的继承用"extends"关键字:
 *      1.抽象类作为父类,它的子类可以是:
 *          a.普通类,必须实现抽象父类中的所有抽象方法
 *          b.抽象类,无需强制实现抽象父类中的抽象方法
 *              但是也可以选择去实现某几个
 *              因为抽象类当中允许实现方法存在
 *
 *     2.抽象类作为子类,它的父类可以是:
 *          a.抽象类.没有任何变化,得到抽象父类的抽象方法和其它成员,可以选择实现抽象方法,也可以做其它一些操作.
 *          b.普通类.没有任何变化,抽象类会完全继承普通类中的成员,毕竟普通类中存在的成员抽象类都允许存在.
 *          而且即便一个抽象类,没有显式继承一个普通类,它也继承Object
 *
 * @since 14:43
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Student s = new Student();
        s.test();
        s.testAbstract();
    }
}

// 抽象Person类
abstract class AbstractPerson {
    int a;
    private int b = 10;
    static int c = 20;
    static final int D = 30;

    public void test() {
    }

    private static void testStatic() {
    }

    // 定义抽象方法
    public abstract void testAbstract();
    public abstract void testAbstract2();

    // 构造代码块
    {
    }

    // 静态代码块
    static {
    }

    public AbstractPerson(int a) {
        this.a = a;
    }

    public AbstractPerson(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public AbstractPerson() {
    }
}

// Class 'Student' must either be declared abstract or implement abstract method 'testAbstract()' in 'AbstractPerson'
/*
    实现父类抽象方法的两种方式:
            1.alt + 回车 类名报错的位置(推荐)
            2.alt + insert
 */
class Student extends AbstractPerson {
    @Override
    public void testAbstract() {
        System.out.println("我是学生子类实现抽象方法");
    }

    @Override
    public void testAbstract2() {
        System.out.println("hello world!");
    }
}

abstract class BaseTeacher extends AbstractPerson{
    @Override
    public void testAbstract() {

    }
}
class A{}
abstract class AbstractA extends A{
    public AbstractA() {
        super();
    }
}


// Illegal combination of modifiers: 'final' and 'abstract'
// abstract final class AbstractPerson{}